AWS Step FunctionsのChoiceステートを使って条件分岐させる
AWS re:Invent 2016で発表された、ビジュアルワークフローを用いて分散アプリケーションを構築するサービス『AWS Step Functions』。
今回は Choice ステートを使って条件に応じて分岐させる方法を紹介します。
なお Step Functions が対応しているステートは以下です。
- Task
- Wait
- Pass
- Succeed
- Fail
- Choice
- Parallel
サンプル 1 : Choice ステートを使った条件分岐
Step Functions の "Choice State" ブループリントです。
FirstState タスク のアウトプットをもとに ChoiceState の Choice によって分岐先を決定します。
具体的にはアウトプットの JSON の foo
属性の値によって
- 整数の 1 なら "FirstMatchState"
- 整数の 2 なら "SecondMatchState"
- それ以外は "DefaultState"
に分岐します。
対応する Amazon States Language は以下です。
ブループリントの Amazon States Language
{ "Comment": "An example of the Amazon States Language using a choice state.", "StartAt": "FirstState", "States": { "FirstState": { "Type": "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME", "Next": "ChoiceState" }, "ChoiceState": { "Type" : "Choice", "Choices": [ { "Variable": "$.foo", "NumericEquals": 1, "Next": "FirstMatchState" }, { "Variable": "$.foo", "NumericEquals": 2, "Next": "SecondMatchState" } ], "Default": "DefaultState" }, "FirstMatchState": { "Type" : "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:OnFirstMatch", "Next": "NextState" }, "SecondMatchState": { "Type" : "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:OnSecondMatch", "Next": "NextState" }, "DefaultState": { "Type": "Fail", "Cause": "No Matches!" }, "NextState": { "Type": "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME", "End": true } } }
Lambda 関数の実装
FirstState タスクの Lambda 関数に { "foo" : 0 OR 1 OR 2 のいずれか}"
を返すものを用意します。
import random def lambda_handler(event, context): return {"foo":random.choice([0,1,2])}
また
- FirstMatchState
- SecondMatchState
の Lambda 関数も、各 Lambda 関数を経由したことがわかるように input に経由した関数名を含めるように一部加工します。
FirstMatchState Lambda Function
def lambda_handler(event, context): event["func_name"] = "onFirstMatch" return event
SecondMatchState Lambda Function
def lambda_handler(event, context): event["func_name"] = "onSecondMatch" return event
(修正版)ブループリントの Amazon States Language
Task のリソース ARN を書き換えたのが次の Amazon States Language です。
NextState ステートは Lambda 関数の実装をサボり、input をそのまま output する Pass タイプにしています。
{ "Comment": "An example of the Amazon States Language using a choice state.", "StartAt": "FirstState", "States": { "FirstState": { "Type": "Task", "Resource": "arn:aws:lambda:eu-west-1:12345:function:OnFirstState", "Next": "ChoiceState" }, "ChoiceState": { "Type" : "Choice", "Choices": [ { "Variable": "$.foo", "NumericEquals": 1, "Next": "FirstMatchState" }, { "Variable": "$.foo", "NumericEquals": 2, "Next": "SecondMatchState" } ], "Default": "DefaultState" }, "FirstMatchState": { "Type" : "Task", "Resource": "arn:aws:lambda:eu-west-1:12345:function:OnFirstMatch", "Next": "NextState" }, "SecondMatchState": { "Type" : "Task", "Resource": "arn:aws:lambda:eu-west-1:12345:function:OnSecondMatch", "Next": "NextState" }, "DefaultState": { "Type": "Fail", "Cause": "No Matches!" }, "NextState": { "Type": "Pass", "End": true } } }
実行例
ステートマシン作成後は "New execution" から実行します。
FirstState ステートは Input に依存しないため、デフォルトのインプットのままステートマシンを実行します。
実行例1
FirstState が
{"foo": 2}
というアウトプットだったため、ChoiceState から SecondMatchState に遷移し、
{"func_name": "onSecondtMatch", "foo": 2}
をアウトプットしています。
実行例2
FirstState が
{"foo": 0}
というアウトプットだったため、ChoiceState から DefaultState に遷移し、Fail タイプによる例外が発生しています。
Choice ステートを使った条件分岐 : サンプル2
Step Functions の Developer マニュアルの Choice ステートのサンプルです。
Start 時のインプットをもとに ChoiceStateX の Choice によって分岐先を決定します。
具体的にはインプットの JSON の type
属性 と value
属性の値によって
- type が "Public" なら "FirstMatchState"
- type が "Private" なら
- value == 0 なら ValueIsZero
- 20 <= value < 30 なら ValueInTwenties
- それ以外は "DefaultState"
に分岐します。
対応する Amazon States Language は以下です。
ブループリントの Amazon States Language
{ "Comment": "Choice", "StartAt": "ChoiceStateX", "States": { "ChoiceStateX": { "Type": "Choice", "Choices": [ { "Not": { "Variable": "$.type", "StringEquals": "Private" }, "Next": "Public" }, { "Variable": "$.value", "NumericEquals": 0, "Next": "ValueIsZero" }, { "And": [ { "Variable": "$.value", "NumericGreaterThanEquals": 20 }, { "Variable": "$.value", "NumericLessThan": 30 } ], "Next": "ValueInTwenties" } ], "Default": "DefaultState" }, "Public": { "Type": "Pass", "Result": "Public", "End": true }, "ValueIsZero": { "Type": "Pass", "Result": "ValueIsZero", "End": true }, "ValueInTwenties": { "Type": "Pass", "Result": "ValueInTwenties", "End": true }, "DefaultState": { "Type": "Fail", "Cause": "No Matches!" } } }
「20台の整数であること」はオペレーター
- And
- NumericGreaterThanEquals
- NumericLessThan
を組み合わせて「20以上かつ30未満」というようにして実現しています。
{ "And": [ { "Variable": "$.value", "NumericGreaterThanEquals": 20 }, { "Variable": "$.value", "NumericLessThan": 30 } ], "Next": "ValueInTwenties" }
実行例
ステートマシン作成後は "New execution" から実行します。 うまく分岐するようにインプットを用意します。
実行例1
{ "type": "Private", "value": 20 }
というインプットに対しては ChoiceStateX から ValueInTwenties に遷移して
"ValueInTwenties"
をアウトプットしています。
実行例2
{ "type": "Public", "value": 20 }
というインプットに対して ChoiceStateX から Public に遷移して
"Public"
をアウトプットしています。
Choice タイプが対応しているオペレーター
今回のサンプルでは、条件に一致されるためのオペレーターとして
- NumericEquals
- NumericGreaterThanEquals
- And
- StringEquals
等を利用しました。
現時点では、以下のオペレーターに対応しています。
- StringEquals
- StringLessThan
- StringGreaterThan
- StringLessThanEquals
- StringGreaterThanEquals
- NumericEquals
- NumericLessThan
- NumericGreaterThan
- NumericLessThanEquals
- NumericGreaterThanEquals
- BooleanEquals
- TimestampEquals
- TimestampLessThan
- TimestampGreaterThan
- TimestampLessThanEquals
- TimestampGreaterThanEquals
- And
- Or
- Not
まとめ
今回は Choice ステートによる条件分岐方法を紹介しました。
String/Numeric/Boolean/Timestamp の比較や And/Or の組み合わせも可能なため、Amazon States Language だけでも複雑な条件を記述することができます。 一方で、ステートマシンの記述言語は JSON ベースなため、なんでも JSON で記述すると、メンテナンスが大変になります。
JSON と Lambda タスクで上手くバランスを取りながらステートを記述することが求められます。